package io.gitee.zhangbinhub.acp.core.common.security

import io.gitee.zhangbinhub.acp.core.common.base.BaseEncrypt
import java.security.KeyFactory
import java.security.Signature
import java.security.interfaces.DSAPrivateKey
import java.security.interfaces.DSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec

/**
 * @author zhang by 10/07/2019
 * @since JDK 11
 */
object DsaEncrypt : BaseEncrypt() {

    private const val ALGORITHM = "DSA"

    /**
     * 签名
     * @param data 待签名数据
     * @param privateKey 私钥
     * @return 签名
     */
    @JvmStatic
    @Throws(Exception::class)
    @JvmOverloads
    fun sign(
        data: String, privateKey: DSAPrivateKey,
        dataEncode: ByteEncodeEnum = ByteEncodeEnum.BYTE,
        signEncode: ByteEncodeEnum = ByteEncodeEnum.BASE64
    ): String {
        val keyBytes = privateKey.encoded
        val pkcs8KeySpec = PKCS8EncodedKeySpec(keyBytes)
        val keyFactory = KeyFactory.getInstance(ALGORITHM)
        val priKey = keyFactory.generatePrivate(pkcs8KeySpec)
        val signature = Signature.getInstance(keyFactory.algorithm)
        signature.initSign(priKey)
        signature.update(decodeToBytes(data, dataEncode))
        return encodeToString(signature.sign(), signEncode)
    }

    /**
     * 验签
     * @param data 待验证数据
     * @param sign 签名
     * @return true|false
     */
    @JvmStatic
    @Throws(Exception::class)
    @JvmOverloads
    fun verify(
        data: String, publicKey: DSAPublicKey, sign: String,
        dataEncode: ByteEncodeEnum = ByteEncodeEnum.BYTE,
        signEncode: ByteEncodeEnum = ByteEncodeEnum.BASE64
    ): Boolean {
        val keyBytes = publicKey.encoded
        val keySpec = X509EncodedKeySpec(keyBytes)
        val keyFactory = KeyFactory.getInstance(ALGORITHM)
        val pubKey = keyFactory.generatePublic(keySpec)
        val signature = Signature.getInstance(keyFactory.algorithm)
        signature.initVerify(pubKey)
        signature.update(decodeToBytes(data, dataEncode))
        return signature.verify(decodeToBytes(sign, signEncode))
    }

}
